package com.xyl.chatrobot.services.impl;

import cn.hutool.crypto.digest.MD5;
import cn.hutool.json.JSONObject;
import com.xyl.chatrobot.services.ChatService;
import com.xyl.chatrobot.util.RandomUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.stereotype.Service;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.util.ObjectUtils;
import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestTemplate;

import java.io.IOException;
import java.net.URLEncoder;
import java.util.*;

/**
 * @author xyl
 * @date 2020-12-14 21:25
 * @desc
 */
@Service
public class ChatServiceImpl implements ChatService {

    @Autowired
    private RestTemplate restTemplate;

    private static final String API_INTERFACE = "https://api.ai.qq.com/fcgi-bin/nlp/nlp_textchat";

    /**
     * 当前会话, 这个随便 ,可自定义生成
     */
    private static final String SESSION = "100001";

    /**
     * 你的app_key
     */
    private static final String APP_KEY = "PQHdn0IJk09pNiGV";

    /**
     * 你的app_id
     */
    private static final String APP_ID = "2160786378";

    @Override
    public String get(String content) {
        Map<String, String> map = new HashMap<>(6);
        map.put("app_id", APP_ID);
        map.put("session", SESSION);
        map.put("question",content);
        //秒级时间戳
        map.put("time_stamp", System.currentTimeMillis() / 1000 + "");
        //随机字符串 , 非空且长度上限32字节
        map.put("nonce_str", RandomUtil.random(10));
        String answer = "";
        try {
            //按照需要生成签名
            map = getSignature(map);
            System.out.println(map);
            //封装请求参数
            MultiValueMap<String, String> mvp = new LinkedMultiValueMap<>();
            map.forEach(mvp::add);
            //设置请求头
            HttpHeaders headers = new HttpHeaders();
            headers.add("Content-Type", "application/x-www-form-urlencoded");
            HttpEntity<MultiValueMap<String, String>> r = new HttpEntity<>(mvp, headers);
            //返回结果
            Map result = restTemplate.postForObject(API_INTERFACE, r, Map.class);
            System.out.println(result);
            if (ObjectUtils.isEmpty(result)) {
                throw new RuntimeException("请求的结果为空!");
            } else {
                if (result.get("ret").toString().equals("0")) {
                    answer = (String) new JSONObject(result.get("data")).get("answer");
                }else{
                    //ret非0 , 请求有误. 返回码参考:https://ai.qq.com/doc/returncode.shtml
                    throw new RuntimeException(result.toString());
                }
            }
        } catch (RestClientException | IOException e) {
            e.printStackTrace();
        }
        return answer;
    }


    /**
     * 生成签名
     * 参考 https://blog.csdn.net/Java_Antelope/article/details/100015942
     */
    private static Map<String, String> getSignature(Map<String, String> params) throws IOException {
        Map<String, String> sortedParams = new TreeMap<>(params);
        Set<Map.Entry<String, String>> entrys = sortedParams.entrySet();
        StringBuilder baseString = new StringBuilder();
        for (Map.Entry<String, String> param : entrys) {
            if (param.getValue() != null && !"".equals(param.getKey().trim()) && !"sign".equals(param.getKey().trim())
                    && !"".equals(param.getValue())) {
                baseString.append(param.getKey().trim()).append("=")
                        .append(URLEncoder.encode(param.getValue(), "UTF-8")).append("&");
            }
        }
        if (baseString.length() > 0) {
            baseString.deleteCharAt(baseString.length() - 1).append("&app_key=").append(APP_KEY);
        }
        try {
            //MD5使用的是 hutool
            String sign = MD5.create().digestHex(baseString.toString()).toUpperCase();
            sortedParams.put("sign", sign);
        } catch (Exception ex) {
            throw new IOException(ex);
        }
        return sortedParams;
    }
}
